
#include "MyImg.h"

#include "imgmanip.h"

void ImgManip::setFilenames(string NameA,string NameB){
	thisImgA.setFilename(NameA);
	thisImgB.setFilename(NameB);
}

double ImgManip::Compare(string var_compare){
    return(Compare(var_compare,"no_options_go_with_default"));
}

double ImgManip::Compare(string var_compare,string option){
	
	if(var_compare=="FFT"){
		cout << "Comparing FFT..." << endl;
		thisImgA.ComputeFFTw();
		thisImgB.ComputeFFTw();
		return(CompareFFT());
	}
	if(var_compare=="HIST"){
		cout << "Comparing histograms..." << endl;
		return(CompareHist());
	}
        if(var_compare=="MMT"){
            cout << "Comparing Moments ..." << endl;
            return(CompareMoments(option));
        }
	
}

double ImgManip::Compare(int method){
    if(method==COMPARE_FFT_GRAY){
        return(CompareFFT(GRAYSCALE_MODE));
    }
    if(method==COMPARE_FFT_R){
        return(CompareFFT(COLOR_MODE_R));
    }
    if(method==COMPARE_FFT_G){
        return(CompareFFT(COLOR_MODE_G));
    }
    if(method==COMPARE_FFT_B){
        return(CompareFFT(COLOR_MODE_B));
    }
    if(method==COMPARE_MOMENTS_I1){
        return(CompareMoments("I1"));
    }
    if(method==COMPARE_MOMENTS_I2){
        return(CompareMoments("I2"));
    }
    if(method==COMPARE_MOMENTS_I3){
        return(CompareMoments("I3"));
    }
    if(method==COMPARE_HIST_GRAY){
        return(CompareHist(GRAYSCALE_MODE));
    }
    if(method==COMPARE_HIST_R){
        return(CompareHist(COLOR_MODE_R));
    }
    if(method==COMPARE_HIST_G){
        return(CompareHist(COLOR_MODE_G));
    }
    if(method==COMPARE_HIST_B){
        return(CompareHist(COLOR_MODE_B));
    }
    cout << "Unknown method!" << endl;
    return(-1);
}

int ImgManip::NameIt(int method,string *general,string *options){
    *general    =   "undefined method";
    *options    =   "undefined method";
    if(method==COMPARE_FFT_GRAY){
        *general    =   "fft";
        *options    =   "grayscale";
    }
    if(method==COMPARE_FFT_R){
        *general    =   "fft";
        *options    =   "red";
    }
    if(method==COMPARE_FFT_G){
        *general    =   "fft";
        *options    =   "green";
    }
    if(method==COMPARE_FFT_B){
        *general    =   "fft";
        *options    =   "blue";
    }
    if(method==COMPARE_MOMENTS_I1){
        *general    =   "moment";
        *options    =   "I1";
    }
    if(method==COMPARE_MOMENTS_I2){
        *general    =   "moment";
        *options    =   "I2";
    }
    if(method==COMPARE_MOMENTS_I3){
        *general    =   "moment";
        *options    =   "I3";
    }
    if(method==COMPARE_HIST_GRAY){
        *general    =   "histogram";
        *options    =   "grayscale";
    }
    if(method==COMPARE_HIST_R){
        *general    =   "histogram";
        *options    =   "red";
    }
    if(method==COMPARE_HIST_B){
        *general    =   "histogram";
        *options    =   "blue";
    }
    if(method==COMPARE_HIST_G){
        *general    =   "histogram";
        *options    =   "green";
    }

    //cout << "Unknown method!" << endl;
    return(0);
}

double ImgManip::CompareFFT(){
	int i,j;
	double tot=0,totA=0,totB=0;
	double aA,aB,bA,bB,norm,im,re;
	
	
	for(j=0;j<thisImgA.getWidth();j++){
		for(i=0;i<thisImgA.getHeight();i++){
			//tot	+=	pow(thisImgA.ValFFT(i,j,true),2)+pow(thisImgA.ValFFT(i,j,false),2)-pow(thisImgB.ValFFT(i,j,true),2)-pow(thisImgB.ValFFT(i,j,false),2);
			//tot	+=	log10(pow(pow(thisImgA.ValFFT(i,j,true),2)+pow(thisImgA.ValFFT(i,j,false),2),.5))/log10(pow(pow(thisImgB.ValFFT(i,j,true),2)+pow(thisImgB.ValFFT(i,j,false),2),.5));
			//tot	+=	pow(thisImgA.ValFFT(i,j,true),2)+pow(thisImgA.ValFFT(i,j,false),2)-pow(thisImgB.ValFFT(i,j,true),2)-pow(thisImgB.ValFFT(i,j,false),2);
			//tot	+=	log10(1+pow(pow(thisImgA.ValFFT(i,j,true),2)+pow(thisImgA.ValFFT(i,j,false),2),.5))-log10(1+pow(pow(thisImgB.ValFFT(i,j,true),2)+pow(thisImgB.ValFFT(i,j,false),2),.5));
			
			//soustrait les 2 complexes
			aA	=	thisImgA.ValFFT(i,j,true);
			aB	=	thisImgB.ValFFT(i,j,true);
			bA	=	thisImgA.ValFFT(i,j,false);
			bB	=	thisImgB.ValFFT(i,j,false);
			
			//tot	+=	pow(thisImgA.ValFFT(i,j,true)*thisImgB.ValFFT(i,j,true)+thisImgA.ValFFT(i,j,false)*thisImgB.ValFFT(i,j,false),2)+pow(thisImgA.ValFFT(i,j,false)+thisImgB.ValFFT(i,j,false),2);
			norm	=	pow(pow(aA*aB+bA*bB,2)	+pow(bB*aA	-bA*aB,2),.5);
			//im	=	pow(0*pow(aA*aB+bA*bB,2)	+pow(bB*aA	-bA*aB,2),.5);
			//re	=	pow(pow(aA*aB+bA*bB,2)	+0*pow(bB*aA	-bA*aB,2),.5);
			tot	+=	norm;
			totA	+=	pow(thisImgA.ValFFT(i,j,true),2)+pow(thisImgA.ValFFT(i,j,false),2);
			totB	+=	pow(thisImgB.ValFFT(i,j,true),2)+pow(thisImgB.ValFFT(i,j,false),2);
			//cout << i << "," << j << ":" <<tot<<';';
		}
	}
	
	return((double)tot/pow(totA*totB,.5));
}
double ImgManip::CompareFFT(int mode){
	int i,j;
	double tot=0,totA=0,totB=0;
	double aA,aB,bA,bB,norm,im,re;

        thisImgA.ComputeFFTwGeneral(mode);
        thisImgB.ComputeFFTwGeneral(mode);

	for(j=0;j<thisImgA.getWidth();j++){
		for(i=0;i<thisImgA.getHeight();i++){
			//tot	+=	pow(thisImgA.ValFFT(i,j,true),2)+pow(thisImgA.ValFFT(i,j,false),2)-pow(thisImgB.ValFFT(i,j,true),2)-pow(thisImgB.ValFFT(i,j,false),2);
			//tot	+=	log10(pow(pow(thisImgA.ValFFT(i,j,true),2)+pow(thisImgA.ValFFT(i,j,false),2),.5))/log10(pow(pow(thisImgB.ValFFT(i,j,true),2)+pow(thisImgB.ValFFT(i,j,false),2),.5));
			//tot	+=	pow(thisImgA.ValFFT(i,j,true),2)+pow(thisImgA.ValFFT(i,j,false),2)-pow(thisImgB.ValFFT(i,j,true),2)-pow(thisImgB.ValFFT(i,j,false),2);
			//tot	+=	log10(1+pow(pow(thisImgA.ValFFT(i,j,true),2)+pow(thisImgA.ValFFT(i,j,false),2),.5))-log10(1+pow(pow(thisImgB.ValFFT(i,j,true),2)+pow(thisImgB.ValFFT(i,j,false),2),.5));

			//soustrait les 2 complexes
			aA	=	thisImgA.ValFFT(i,j,true,mode);
			aB	=	thisImgB.ValFFT(i,j,true,mode);
			bA	=	thisImgA.ValFFT(i,j,false,mode);
			bB	=	thisImgB.ValFFT(i,j,false,mode);

			//tot	+=	pow(thisImgA.ValFFT(i,j,true)*thisImgB.ValFFT(i,j,true)+thisImgA.ValFFT(i,j,false)*thisImgB.ValFFT(i,j,false),2)+pow(thisImgA.ValFFT(i,j,false)+thisImgB.ValFFT(i,j,false),2);
			norm	=	pow(pow(aA*aB+bA*bB,2)	+pow(bB*aA	-bA*aB,2),.5);
			//im	=	pow(0*pow(aA*aB+bA*bB,2)	+pow(bB*aA	-bA*aB,2),.5);
			//re	=	pow(pow(aA*aB+bA*bB,2)	+0*pow(bB*aA	-bA*aB,2),.5);
			tot	+=	norm;
			totA	+=	pow(thisImgA.ValFFT(i,j,true,mode),2)+pow(thisImgA.ValFFT(i,j,false,mode),2);
			totB	+=	pow(thisImgB.ValFFT(i,j,true,mode),2)+pow(thisImgB.ValFFT(i,j,false,mode),2);
			//cout << i << "," << j << ":" <<tot<<';';
		}
	}
        if(tot>totA*totB){
            tot=totA*totB;
        }
	return( pow(1.0-pow((double)tot,2) / (totA*totB) ,.5) );
}

double ImgManip::CompareHist(){
	
	char text [16];
	int i, hist_size = 256, sch = 0;
	float range_0 [] = {0, 256};
	float * ranges [] = {range_0};
	double tmp, dist = 0;
	IplImage * src_img1 = 0, * src_img2 = 0, * dst_img1 [4] = {0, 0, 0, 0}, * dst_img2 [4] = {0, 0, 0, 0};
	CvHistogram * hist1, * hist2;
	CvFont font;
	CvSize text_size;
	// (1) to load the two images. If you are not equal the number of channels, end 
	src_img1 = cvLoadImage (thisImgA.getFilename().data(), CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
	src_img2 = cvLoadImage (thisImgB.getFilename().data(), CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
	
	if (src_img1 == 0 || src_img2 == 0)
		return -1;
	if (src_img1-> nChannels!= src_img2->nChannels)
		return -1;
	// (2) the number of input channels of the image area images of 
	sch = src_img1->nChannels;
	for (i = 0; i <sch; i ++){
		dst_img1 [i] = cvCreateImage (cvSize (src_img1-> width, src_img1-> height), src_img1-> depth, 1);
		dst_img2 [i] = cvCreateImage (cvSize (src_img2-> width, src_img2-> height), src_img2-> depth, 1);
	}
	// (3) to secure the structure histogram 
	hist1 = cvCreateHist (1, & hist_size, CV_HIST_ARRAY, ranges, 1);
	hist2 = cvCreateHist (1, & hist_size, CV_HIST_ARRAY, ranges, 1);
	// (4) In the case of multi-channel input images, each image into a channel 
	if (sch == 1) {
		cvCopy (src_img1, dst_img1 [0], NULL);
		cvCopy (src_img2, dst_img2 [0], NULL);
	}
	else{
		cvSplit (src_img1, dst_img1 [0], dst_img1 [1], dst_img1 [2], dst_img1 [3]);
		cvSplit (src_img2, dst_img2 [0], dst_img2 [1], dst_img2 [2], dst_img2 [3]);
	}
	// (5) histogram calculations, the normalized distance call 
	for(i = 0; i <sch; i ++){
		cvCalcHist (& dst_img1 [i], hist1, 0, NULL);
		cvCalcHist (& dst_img2 [i], hist2, 0, NULL);
		cvNormalizeHist (hist1, 10000);
		cvNormalizeHist (hist2, 10000);
		tmp = cvCompareHist (hist1, hist2, CV_COMP_BHATTACHARYYA);
		dist += tmp * tmp;
	}
	dist = sqrt (dist);
	// (6) sought to distance drawn characters in the picture as 
	snprintf (text, 16, "Distance =%.3f", dist);
	cvInitFont (& font, CV_FONT_HERSHEY_SIMPLEX, 2.0, 2.0, 0, 4, 8);
	cvPutText (src_img2, text, cvPoint (10, src_img2-> height - 10), & font, cvScalarAll (0));
	cvGetTextSize ( "Input1", & font, & text_size, 0);
	cvPutText (src_img1, "Input1", cvPoint (10, text_size.height), & font, cvScalarAll (0));
	cvPutText (src_img2, "Input2", cvPoint (10, text_size.height), & font, cvScalarAll (0));
	// (7) show images of the two, ending when a key is pressed 
	/*
	cvNamedWindow ( "Image1", CV_WINDOW_AUTOSIZE);
	cvNamedWindow ( "Image2", CV_WINDOW_AUTOSIZE);
	cvShowImage ( "Image1", src_img1);
	cvShowImage ( "Image2", src_img2);
	cvWaitKey (0);
	cvDestroyWindow ( "Image1");
	cvDestroyWindow ( "Image2");
	 **/
	for (i = 0; i <src_img1-> nChannels; i ++){
		cvReleaseImage (& dst_img1 [i]);
		cvReleaseImage (& dst_img2 [i]);
	}
	cvReleaseImage (& src_img1);
	cvReleaseImage (& src_img2);
	cvReleaseHist (& hist1);
	cvReleaseHist (& hist2);
	
	return(dist);
}

double ImgManip::CompareHist(int mode){

	char text [16];
	int i, hist_size = 256, sch = 0;
	float range_0 [] = {0, 256};
	float * ranges [] = {range_0};
	double tmp, dist = 0;
	IplImage * src_img1 = 0, * src_img2 = 0, * dst_img1 [4] = {0, 0, 0, 0}, * dst_img2 [4] = {0, 0, 0, 0};
	CvHistogram * hist1, * hist2;
	CvFont font;
	CvSize text_size;
	// (1) to load the two images. If you are not equal the number of channels, end
        GenerateMonochrome(mode,thisImgA.getFilename(),"tempA.png");
        GenerateMonochrome(mode,thisImgB.getFilename(),"tempB.png");
	src_img1 = cvLoadImage ("tempA.png", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
	src_img2 = cvLoadImage ("tempB.png", CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);

	if (src_img1 == 0 || src_img2 == 0)
		return -1;
	if (src_img1-> nChannels!= src_img2->nChannels)
		return -1;
	// (2) the number of input channels of the image area images of
	sch = src_img1->nChannels;
	for (i = 0; i <sch; i ++){
		dst_img1 [i] = cvCreateImage (cvSize (src_img1-> width, src_img1-> height), src_img1-> depth, 1);
		dst_img2 [i] = cvCreateImage (cvSize (src_img2-> width, src_img2-> height), src_img2-> depth, 1);
	}
	// (3) to secure the structure histogram
	hist1 = cvCreateHist (1, & hist_size, CV_HIST_ARRAY, ranges, 1);
	hist2 = cvCreateHist (1, & hist_size, CV_HIST_ARRAY, ranges, 1);
	// (4) In the case of multi-channel input images, each image into a channel
	if (sch == 1) {
		cvCopy (src_img1, dst_img1 [0], NULL);
		cvCopy (src_img2, dst_img2 [0], NULL);
	}
	else{
		cvSplit (src_img1, dst_img1 [0], dst_img1 [1], dst_img1 [2], dst_img1 [3]);
		cvSplit (src_img2, dst_img2 [0], dst_img2 [1], dst_img2 [2], dst_img2 [3]);
	}
	// (5) histogram calculations, the normalized distance call
	for(i = 0; i <sch; i ++){
		cvCalcHist (& dst_img1 [i], hist1, 0, NULL);
		cvCalcHist (& dst_img2 [i], hist2, 0, NULL);
		cvNormalizeHist (hist1, 10000);
		cvNormalizeHist (hist2, 10000);
		tmp = cvCompareHist (hist1, hist2, CV_COMP_BHATTACHARYYA);
		dist += tmp * tmp;
	}
	dist = sqrt (dist);
	// (6) sought to distance drawn characters in the picture as
	snprintf (text, 16, "Distance =%.3f", dist);
	cvInitFont (& font, CV_FONT_HERSHEY_SIMPLEX, 2.0, 2.0, 0, 4, 8);
	cvPutText (src_img2, text, cvPoint (10, src_img2-> height - 10), & font, cvScalarAll (0));
	cvGetTextSize ( "Input1", & font, & text_size, 0);
	cvPutText (src_img1, "Input1", cvPoint (10, text_size.height), & font, cvScalarAll (0));
	cvPutText (src_img2, "Input2", cvPoint (10, text_size.height), & font, cvScalarAll (0));
	// (7) show images of the two, ending when a key is pressed
	/*
	cvNamedWindow ( "Image1", CV_WINDOW_AUTOSIZE);
	cvNamedWindow ( "Image2", CV_WINDOW_AUTOSIZE);
	cvShowImage ( "Image1", src_img1);
	cvShowImage ( "Image2", src_img2);
	cvWaitKey (0);
	cvDestroyWindow ( "Image1");
	cvDestroyWindow ( "Image2");
	 **/
	for (i = 0; i <src_img1-> nChannels; i ++){
		cvReleaseImage (& dst_img1 [i]);
		cvReleaseImage (& dst_img2 [i]);
	}
	cvReleaseImage (& src_img1);
	cvReleaseImage (& src_img2);
	cvReleaseHist (& hist1);
	cvReleaseHist (& hist2);

	return(dist);
}


double ImgManip::CompareMoments(string options){
    IplImage * src_img1 = 0, * src_img2 = 0;
    IplImage * dst_img1 = 0, * dst_img2 = 0;
    int opt;
    double temp;
    opt =   CV_CONTOURS_MATCH_I1;
    if(options=="I2"){
        opt =   CV_CONTOURS_MATCH_I2;
    }
    else{
        if(options=="I3"){
            opt =   CV_CONTOURS_MATCH_I3;
        }
    }
    
    dst_img1 = cvLoadImage (thisImgA.getFilename().data());
    dst_img2 = cvLoadImage (thisImgB.getFilename().data());
/*
    cvAdaptiveThreshold( dst_img1->imageData, src_img1->imageData,1.1,CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY,
                          3, 0 .0);*/
    src_img1 = cvCreateImage( cvGetSize( dst_img1 ), 8, 1 );
    src_img2 = cvCreateImage( cvGetSize( dst_img2 ), 8, 1 );
    cvCvtColor( dst_img1, src_img1, CV_BGR2GRAY );
    cvCvtColor( dst_img2, src_img2, CV_BGR2GRAY );
    cvThreshold( src_img1, src_img1, 100, 255, CV_THRESH_BINARY );
    cvThreshold( src_img2, src_img2, 100, 255, CV_THRESH_BINARY );


    //cvFindContours( g_gray, g_storage, &contours );


    CvSeq *contorno1, *contorno2;
    CvMemStorage *storage=cvCreateMemStorage(0);
    //restituisce i contorni trovati in una CvSeq disponendo i contorni su due livelli
    //1° livello: contorni esterni;
    //2° livello: contorni interni (hole);
    cvFindContours(src_img1,storage,&contorno1,sizeof(CvContour),CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE);
    cvFindContours(src_img2,storage,&contorno2,sizeof(CvContour),CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE);
    //ci spostiamo dal livello esterno (cornice dell'immagine) al secondo livello
    //contorni degli oggetti presenti nell'immagine.
    //contorno1   =   contorno1->v_next;
    //contorno2   =   contorno2->v_next;
    temp        =   cvMatchShapes( contorno1, contorno2, opt);
    /*
    cout << "temp:" << temp << endl;
    cout << "opts:" << opt << endl;
     **/

    //temp    =   cvMatchShapes(src_img1->imageData,src_img2->imageData,CV_CONTOURS_MATCH_I2,0);

    cvReleaseImage (& src_img1);
    cvReleaseImage (& src_img2);
    cvReleaseImage (& dst_img1);
    cvReleaseImage (& dst_img2);

    return(temp);
}

void ImgManip::GenerateMonochrome(int mode,string Filename,string outfname){
    IplImage *temp;
    unsigned char* ptr=NULL;
    unsigned char* ptemp=NULL;
    IplImage* animg;
    int k,j,l;

    if(mode == GRAYSCALE_MODE){
        animg	=cvLoadImage(Filename.data(), CV_LOAD_IMAGE_GRAYSCALE );
        cvSaveImage(outfname.data(),animg);
        cvReleaseImage(&animg);
        return;
    }

    animg     =cvLoadImage(Filename.data(), CV_LOAD_IMAGE_COLOR );

    ptr     =(unsigned char*) animg->imageData;

    temp    =cvCreateImage( cvGetSize(animg),
                            animg->depth,
                            CV_LOAD_IMAGE_GRAYSCALE);

    ptemp   =(unsigned char*) temp->imageData;

    for(k=0;k<animg->height;k++){
        l=0;
        //cout << "test1" << endl;
        for(j=0;j<animg->width*animg->nChannels;j+=animg->nChannels){
            ptemp[l]    =ptr[j+(mode-2)];
            l++;
        }
        //cout << "l" << l << endl;
        ptr+=   animg->widthStep;
        ptemp+= temp->widthStep;
    }
    cvSaveImage(outfname.data(),temp);
    cvReleaseImage(&animg);
    cvReleaseImage(&temp);
    //thisimg     =cvLoadImage("temp.png", CV_LOAD_IMAGE_GRAYSCALE );
}
